namespace Example.Models
{
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Models;
    using SimpleWebServices.Security.Cryptography;
    using Xunit;

    public sealed class ContactFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Contact>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("contact")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            Contact expected = new Contact
            {
                Choice = 2,
                Email = "john.doe@example.com",
                Name = "John Doe",
                Message = "The message text."
            };

            Contact actual = "<contact email='john.doe@example.com' name='John Doe' choice='2'><message>The message text.</message></contact>".Deserialize<Contact>();

            Assert.Equal<Contact>(expected, actual);
        }

        [Fact]
        public void deserializeEmpty()
        {
            Contact expected = new Contact();
            Contact actual = "<contact/>".Deserialize<Contact>();

            Assert.Equal<Contact>(expected, actual);
        }

        [Fact]
        public void serialize()
        {
            Contact obj = new Contact
            {
                Choice = 2,
                Email = "john.doe@example.com",
                Name = "John Doe",
                Message = "The message text."
            };

            IXPathNavigable xml = obj.Serialize();

            string xpath = "1=count(/contact[@email='john.doe@example.com'][@name='John Doe'][@choice='2']/message[text()='The message text.'])";

            Assert.True((bool)xml.CreateNavigator().Evaluate(xpath));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Contact());
        }

        [Fact]
        public void ctor_FormSession()
        {
            string email = "john.doe@example.com";
            string name = "John Doe";
            string message = "The message text.";

            Contact expected = new Contact
            {
                Choice = 2,
                Email = email,
                Name = name,
                Message = message,
                TermsAndConditions = true
            };

            Contact actual = new Contact(new FormSession
            {
                Data = new DataCollection
                {
                    { "choice", "2" },
                    { "email", email },
                    { "name", name },
                    { "message", message },
                    { "terms_and_conditions", null }
                }
            });

            Assert.Equal<Contact>(expected, actual);
        }

        [Fact]
        public void ctor_FormSessionNull()
        {
            Contact expected = new Contact();
            Contact actual = new Contact(null as FormSession);

            Assert.Equal<Contact>(expected, actual);
        }

        [Fact]
        public void prop_Choice()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Choice"))
                .XmlAttribute("choice")
                .IsAutoProperty<int>()
                .Result);
        }

        [Fact]
        public void prop_Email()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Email"))
                .XmlAttribute("email")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Entity"))
                .XmlIgnore()
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            Contact obj = (
                "<contact email='john.doe@example.com' name='John Doe' choice='2'>" +
                    "<message>The message text.</message>" +
                "</contact>").Deserialize<Contact>();

            string expected = "c1TOuYKgshUYpBGuQW0i/g==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new Contact().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Name()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Name"))
                .XmlAttribute("name")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Message()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Message"))
                .XmlElement("message")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Token()
        {
            Assert.True(new PropertyExpectations(typeof(Contact).GetProperty("Token"))
                .XmlIgnore()
                .IsAutoProperty<Token?>()
                .Result);
        }
    }
}